#include "mymath.h"


vec3::vec3( float _x, float _y, float _z ) : x(_x), y(_y), z(_z)
{

}

vec3::vec3() : x(0), y(0), z(0)
{

}

vec3 vec3::operator+( const vec3& rhs ) const
{
	return vec3(x + rhs.x, y + rhs.y, z + rhs.z);
}

vec3 vec3::operator-() const
{
	return vec3(-x, -y, -z);
}

vec3& vec3::Normalize()
{
	float norm = this->Norm();
	if (norm != 0)
	{
		*this *= 1.0f / norm;
	}
	return *this;
}

vec3& vec3::operator*=( float rhs )
{
	x *= rhs;
	y *= rhs;
	z *= rhs;
	return *this;
}

float vec3::Norm()
{
	float dp = dot(*this, *this);
	return sqrtf(dp);
}

vec3 vec3::operator*( float rhs ) const
{
	return vec3(x * rhs, y * rhs, z * rhs);
}

vec3 vec3::operator-( const vec3& rhs ) const
{
	return *this + ( - rhs);
}


float dot( const vec3& lhs, const vec3& rhs )
{
	return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z;
}

mat4 MatrixLookAt( vec3& pos, vec3& target, vec3& up )
{
	mat4 m;

	/*vec3 N = (target - pos).Normalize();
	vec3 U = up.Normalize();
	U = cross(U, N);
	vec3 V = cross(N, U);*/

	vec3 zaxis = (target - pos).Normalize();
	vec3 xaxis = (cross(up, zaxis)).Normalize();
	vec3 yaxis = cross(zaxis, xaxis);
	
	m(0,0) = xaxis.x; m(0, 1) = xaxis.y; m(0, 2) = xaxis.z; m(0, 3) = -dot(xaxis,pos);
	m(1,0) = yaxis.x; m(1, 1) = yaxis.y; m(1, 2) = yaxis.z; m(1, 3) = -dot(yaxis,pos);
	m(2,0) = zaxis.x; m(2, 1) = zaxis.y; m(2, 2) = zaxis.z; m(2, 3) = -dot(zaxis,pos);
	m(3,0) = 0;       m(3, 1) = 0;       m(3, 2) = 0;       m(3, 3) = 1.0f;

	/*m(0,0) = xaxis.x; m(0, 1) = xaxis.y; m(0, 2) = xaxis.z; m(0, 3) = pos.x;
	m(1,0) = yaxis.x; m(1, 1) = yaxis.y; m(1, 2) = yaxis.z; m(1, 3) = pos.y;
	m(2,0) = zaxis.x; m(2, 1) = zaxis.y; m(2, 2) = zaxis.z; m(2, 3) = pos.z;
	m(3,0) = 0;   m(3, 1) = 0;   m(3, 2) = 0;   m(3, 3) = 1.0f;
*/
	return m;
}

vec3 cross( const vec3& lhs, const vec3& rhs )
{
	const float _x = lhs.y * rhs.z - lhs.z * rhs.y;
	const float _y = lhs.z * rhs.x - lhs.x * rhs.z;
	const float _z = lhs.x * rhs.y - lhs.y * rhs.x;

	return vec3(_x, _y, _z);
}

mat4 MatrixPerspectiveFOV( float FOV, float Width, float Height, float zNear, float zFar )
{

	mat4 m;
	const float ar         = Width / Height;
	const float zRange     = zFar - zNear;
	const float tanHalfFOV = tanf((FOV));

	m(0,0) = 1.0f/(tanHalfFOV * ar);	m(0, 1) = 0.0f;					m(0, 2) = 0.0f;				m(0, 3) = 0.0f;
	m(1,0) = 0.0f;						m(1, 1) = 1.0f/tanHalfFOV;		m(1, 2) = 0.0f;				m(1, 3) = 0.0f;
	m(2,0) = 0.0f;						m(2, 1) = 0.0f;					m(2, 2) = zFar/zRange ;	    m(2, 3) = -zFar*zNear/zRange;
	m(3,0) = 0.0f;						m(3, 1) = 0.0f;					m(3, 2) = 1.0f;				m(3, 3) = 0.0f;

	return m;
}

mat4 MatrixScale( float x, float y, float z )
{
	mat4 m;
	m(0,0) = x;
	m(1,1) = y;
	m(2,2) = z;

	return m;

}

//build a translation matrix
mat4 TranslateMatrix( float x, float y, float z)
{
	mat4 m;
	m(0,3) = x;
	m(1,3) = y;
	m(2,3) = z;

	return m;
}

mat4 mat4::t() const
{
	mat4 m;
	mat4 r = *this;
	
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			m(i, j) = r(j , i);
		}
	}

	return m;
}

vec2::vec2( float _x, float _y ) : x(_x), y(_y)
{

}

vec2::vec2() : x(0), y(0)
{

}